package com.hhf.cloud.service.impl;

import com.hhf.cloud.entities.DtxStorage;
import com.hhf.cloud.entities.DtxStorageFreeze;
import com.hhf.cloud.mapper.DtxStorageFreezeMapper;
import com.hhf.cloud.mapper.DtxStorageMapper;
import com.hhf.cloud.service.StorageTccService;
import lombok.extern.slf4j.Slf4j;
import org.apache.seata.core.context.RootContext;
import org.apache.seata.rm.tcc.api.BusinessActionContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import tk.mybatis.mapper.entity.Example;

/**
 * @author Daniel-黄海峰
 * @Description
 * @create 2024/3/3 11:29
 */
@Slf4j
@Service
public class StorageTccServiceImpl implements StorageTccService {
    @Autowired
    private DtxStorageMapper dtxStorageMapper;

    @Autowired
    private DtxStorageFreezeMapper dtxStorageFreezeMapper;

    /**
     * try方法
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean decreaseTcc(BusinessActionContext ctx, Long productId, Integer count) {
        String xid = RootContext.getXID();
        // 业务悬挂判断，避免空悬挂，已经执行过回滚了就不能再预留资源
        // dtx_storage_freeze表中是否有冻结记录，等于null正确，如果有一定是CANCEL执行过，拒绝业务悬挂
        DtxStorageFreeze dtxStorageFreezeFromDB = dtxStorageFreezeMapper.selectByPrimaryKey(xid);
        if (dtxStorageFreezeFromDB != null) {
            // CANCEL执行过，拒绝业务往下走
            return true;
        }

        // 库存资源是否充足判断
        Example wherCondition = new Example(DtxStorage.class);
        Example.Criteria criteria = wherCondition.createCriteria();
        criteria.andEqualTo("productId", productId);
        DtxStorage dtxStorage = dtxStorageMapper.selectOneByExample(wherCondition);
        if (count > dtxStorage.getTotalAmount()) throw new RuntimeException("库存已不足，预占资源失败");

        // dtx_storage库存数量冻减
        dtxStorageMapper.decreaseTcc(productId, count.longValue());

        // dtx_storage_freeze表中的TCC冻结情况
        DtxStorageFreeze dtxStorageFreeze = new DtxStorageFreeze();
        dtxStorageFreeze.setXid(RootContext.getXID());
        dtxStorageFreeze.setProductId(productId);
        dtxStorageFreeze.setFreezeAmount(count);
        dtxStorageFreeze.setTccStatus(DtxStorageFreeze.TccStatusEnum.TRY);

        dtxStorageFreezeMapper.insertSelective(dtxStorageFreeze);
        return true;
    }

    /**
     * Confirm
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean commit(BusinessActionContext actionContext) {
        System.out.println("--------come in confirm ctx.getXid(): " + actionContext.getXid());
        // 幂等性判断，delete操作删除1次和100次相同，天生幂等性
        // 修改订单状态，从try→confirm或者你不想保留直接删除t_storage_freeze里面的TRY状态数据
        int i = dtxStorageFreezeMapper.deleteByPrimaryKey(actionContext.getXid());
        return i == 1;
    }

    /**
     * Cancel
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean rollback(BusinessActionContext actionContext) {
        System.out.println("--------come in cancel ctx.getXid(): " + actionContext.getXid());
        DtxStorageFreeze dtxStorageFreeze = dtxStorageFreezeMapper.selectByPrimaryKey(actionContext.getXid());
        // 空回滚判断,允许空回滚存在，冻结账户为null说明try没有执行，需要空回滚处理
        if (dtxStorageFreeze == null) {
            // 说明try没有执行，需要空回滚处理
            DtxStorageFreeze dtxStorageFreezeNullRollBack = new DtxStorageFreeze();
            dtxStorageFreezeNullRollBack.setXid(actionContext.getXid());
            dtxStorageFreezeNullRollBack.setFreezeAmount(0);
            dtxStorageFreezeNullRollBack.setProductId(Long.valueOf(actionContext.getActionContext("productId").toString()));
            dtxStorageFreezeNullRollBack.setTccStatus(DtxStorageFreeze.TccStatusEnum.CANCEL);
            dtxStorageFreezeMapper.insertSelective(dtxStorageFreezeNullRollBack);
            return true;
        }
        // 判断幂等性
        if (dtxStorageFreeze.getTccStatus() == DtxStorageFreeze.TccStatusEnum.CANCEL) {
            // 已经Cancel过了，不要重复处理了,保证幂等性
            return true;
        }
        // 回退库存数量冻减
        Long sum = Long.valueOf(dtxStorageFreeze.getFreezeAmount());//数量
        Long productId = dtxStorageFreeze.getProductId();//商品id
        dtxStorageMapper.undecreaseTcc(productId, sum);

        // 冻结账户金额清零并修改状态为CANCEL
        dtxStorageFreeze.setFreezeAmount(0);
        dtxStorageFreeze.setTccStatus(DtxStorageFreeze.TccStatusEnum.CANCEL);
        int i = dtxStorageFreezeMapper.updateByPrimaryKey(dtxStorageFreeze);

        return i == 1;
    }
}
